package org.gdstash.db;

import org.gdstash.util.GDMsgFormatter;
import org.gdstash.util.GDMsgLogger;

import java.sql.*;
import java.util.LinkedList;
import java.util.List;

public class DBConstellationAffinity implements Comparable<DBConstellationAffinity> {
    private static final String TABLE_NAME = "GDC_CONSTELLATION_AFFINITY";
    private static final int ROW_CONSTELLATION_ID = 1;
    private static final int ROW_AFFINITY = 2;
    private static final int ROW_REQUIRED = 3;
    private static final int ROW_POINTS = 4;
    private String constellationID;
    private String affinity;
    private boolean required;
    private int points;
    private int index;

    @Override
    public boolean equals(final Object o) {
        if (o == null) {
            return false;
        }
        if (!o.getClass().equals(DBConstellationAffinity.class)) {
            return false;
        }
        final DBConstellationAffinity affinity = (DBConstellationAffinity) o;
        return affinity.constellationID.equals(this.constellationID);
    }

    @Override
    public int hashCode() {
        int hash = this.constellationID.hashCode();
        hash += this.index;
        if (this.required) {
            hash += 100;
        }
        return hash;
    }

    @Override
    public int compareTo(final DBConstellationAffinity o) {
        if (!o.getClass().equals(DBConstellationAffinity.class)) {
            final Object[] args = {DBConstellationAffinity.class, o.toString()};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_NOT_OF_TYPE", args);
            throw new ClassCastException(msg);
        }
        final DBConstellationAffinity affinity = o;
        final int comp = this.constellationID.compareTo(affinity.constellationID);
        if (comp != 0) {
            return comp;
        }
        if (this.required) {
            if (!affinity.required) {
                return -1;
            }
        } else if (affinity.required) {
            return 1;
        }
        return this.index - affinity.index;
    }

    public String getAffinity() {
        return this.affinity;
    }

    public void setAffinity(final String affinity) {
        this.affinity = affinity;
    }

    public boolean isRequired() {
        return this.required;
    }

    public void setRequired(final boolean required) {
        this.required = required;
    }

    public int getPoints() {
        return this.points;
    }

    public void setPoints(final int points) {
        this.points = points;
    }

    public int getIndex() {
        return this.index;
    }

    public void setIndex(final int index) {
        this.index = index;
    }

    public static void createTable() throws SQLException {
        final String dropTable = "DROP TABLE GDC_CONSTELLATION_AFFINITY";
        final String createTable = "CREATE TABLE GDC_CONSTELLATION_AFFINITY (CONSTELLATION_ID VARCHAR(256) NOT NULL, AFFINITY         VARCHAR(32) NOT NULL, REQUIRED         BOOLEAN, POINTS           INTEGER, PRIMARY KEY (CONSTELLATION_ID, AFFINITY, REQUIRED))";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final Statement st = conn.createStatement()) {
                if (GDDBUtil.tableExists(conn, "GDC_CONSTELLATION_AFFINITY")) {
                    st.execute(dropTable);
                }
                st.execute(createTable);
                st.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                throw ex;
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static void delete(final Connection conn, final String itemSetID) throws SQLException {
        final String deleteEntry = "DELETE FROM GDC_CONSTELLATION_AFFINITY WHERE CONSTELLATION_ID = ?";
        try (final PreparedStatement ps = conn.prepareStatement(deleteEntry)) {
            ps.setString(1, itemSetID);
            ps.executeUpdate();
            ps.close();
        } catch (SQLException ex) {
            throw ex;
        }
    }

    public static void insert(final Connection conn, final DBConstellation dbConstellation) throws SQLException {
        if (dbConstellation.getStarList() == null) {
            return;
        }
        if (dbConstellation.getStarList().isEmpty()) {
            return;
        }
        final String insert = "INSERT INTO GDC_CONSTELLATION_AFFINITY VALUES (?,?,?,?)";
        try (final PreparedStatement ps = conn.prepareStatement(insert)) {
            for (final DBConstellationAffinity dbAffinity : dbConstellation.getAffinityList()) {
                if (dbAffinity.getAffinity() == null) {
                    continue;
                }
                if (dbAffinity.getAffinity().isEmpty()) {
                    continue;
                }
                ps.setString(1, dbConstellation.getConstellationID());
                ps.setString(2, dbAffinity.getAffinity());
                ps.setBoolean(3, dbAffinity.isRequired());
                ps.setInt(4, dbAffinity.getPoints());
                ps.executeUpdate();
                ps.clearParameters();
            }
            ps.close();
            conn.commit();
        } catch (SQLException ex) {
            throw ex;
        }
    }

    public static List<DBConstellationAffinity> getByConstellationID(final String constellationID) {
        List<DBConstellationAffinity> dbAffinities = null;
        final String command = "SELECT * FROM GDC_CONSTELLATION_AFFINITY WHERE CONSTELLATION_ID = ?";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, constellationID);
            try (final ResultSet rs = ps.executeQuery()) {
                dbAffinities = wrap(rs);
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {constellationID, "GDC_CONSTELLATION_AFFINITY"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return dbAffinities;
    }

    private static List<DBConstellationAffinity> wrap(final ResultSet rs) throws SQLException {
        final LinkedList<DBConstellationAffinity> list = new LinkedList<DBConstellationAffinity>();
        while (rs.next()) {
            final DBConstellationAffinity affinity = new DBConstellationAffinity();
            affinity.constellationID = rs.getString(1);
            affinity.affinity = rs.getString(2);
            affinity.required = rs.getBoolean(3);
            affinity.points = rs.getInt(4);
            list.add(affinity);
        }
        return list;
    }
}
